package com.ting.mybatis.parse;

import com.ting.mybatis.config.MyConfiguration;
import com.ting.mybatis.config.MyEnvironment;
import com.ting.mybatis.config.MyMapperStatement;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * *解析xml
 * mybatis源码中用xpath解析，基于路径表达式解析
* */

public class MyXMLConfigBuilder {

    /**
    * XPath解析xml
    * */
    private MyXPathParser myXPathParser;

    /**
     * 构造方法中对xpath解析器对象初始化
     * 和将xml文件解析为document文档
     */
    public MyXMLConfigBuilder(InputStream inputStream) {
        this.myXPathParser=new MyXPathParser(inputStream);
    }

    /**
     * 得到了XPath解析后的xml
     * 和xml的document文档
     * 在这里做一个真正的解析，返回MyConfiguration对象
     * 把xml文档中解析出来的具体数据，封装到MyConfiguration对象里
     */

    public MyConfiguration parse(){
        //xpath表达式解析方法中，xNode方法解析xml节点
        Node dataSourceNode=myXPathParser.xNode("/configuration/environments/environment/dataSource");

        //解析数据源属性配置信息
        Properties properties=new Properties();
        NodeList propertyNodeList=dataSourceNode.getChildNodes();
        for(int i=0;i<((NodeList) propertyNodeList).getLength();i++){
            Node propertyNode=propertyNodeList.item(i);
            if(propertyNode.getNodeType()==Node.ELEMENT_NODE){
                properties.setProperty(propertyNode.getAttributes().getNamedItem("name").getNodeValue(),propertyNode.getAttributes().getNamedItem("value").getNodeValue());
            }
        }

        //读完之后放进来
        MyEnvironment myEnvironment=new MyEnvironment();
        myEnvironment.setDriver(properties.getProperty("driver"));
        myEnvironment.setPassword(properties.getProperty("password"));
        myEnvironment.setUsername(properties.getProperty("username"));
        myEnvironment.setUrl(properties.getProperty("url"));

        //解析Mapper
        Map<String, MyMapperStatement> mapperStatementMap=new ConcurrentHashMap<String,MyMapperStatement>();
        Node mappersNode=myXPathParser.xNode("/configuration/mappers");
        NodeList mapperNodeList=mappersNode.getChildNodes();
        for(int i=0;i<mapperNodeList.getLength();i++){
            Node mapperNode=mapperNodeList.item(i);
            if(mapperNode.getNodeType()==Node.ELEMENT_NODE){
                String resource=mapperNode.getAttributes().getNamedItem("resource").getNodeValue();
                InputStream inputStream=this.getClass().getClassLoader().getResourceAsStream(resource);
                this.myXPathParser=new MyXPathParser(inputStream);
                Element element=myXPathParser.getDocument().getDocumentElement();
                String namespace=element.getAttribute("namespace");
                NodeList sqlNodeList=element.getChildNodes();

                for(int ii=0;ii<sqlNodeList.getLength();ii++){
                    Node sqlNode=sqlNodeList.item(ii);
                    if(sqlNode.getNodeType()==Node.ELEMENT_NODE){
                        String id="";
                        String resultType="";
                        String parameterType="";

                        Node idNode=sqlNode.getAttributes().getNamedItem("id");
                        if(null==idNode){
                            throw new RuntimeException("sql id is null.");
                        }else{
                            id=sqlNode.getAttributes().getNamedItem("id").getNodeValue();
                        }
                        Node resultTypeNode=sqlNode.getAttributes().getNamedItem("resultType");
                        if(null!=resultTypeNode){
                            resultType=sqlNode.getAttributes().getNamedItem("resultType").getNodeValue();
                        }
                        Node parameterTypeNode=sqlNode.getAttributes().getNamedItem("parameterType");
                        if(null!=parameterTypeNode){
                            parameterType=sqlNode.getAttributes().getNamedItem("parameterType").getNodeValue();
                        }

                        String sql=sqlNode.getTextContent();

                        MyMapperStatement mapperStatement=new MyMapperStatement();
                        mapperStatement.setId(id);
                        mapperStatement.setNamespace(parameterType);
                        mapperStatement.setParameterType(resultType);
                        mapperStatement.setResultType(resultType);
                        mapperStatement.setSql(sql);

                        //map的key=namespace+"."+id
                        mapperStatementMap.put(namespace+"."+id,mapperStatement);
                    }
                }
            }
        }

        //把解析出来的值赋给MyConfiguration
        MyConfiguration myConfiguration=new MyConfiguration();

        //mybatis-config.xml
        myConfiguration.setMyEnvironment(myEnvironment);

        //xxxMapper.xml
        myConfiguration.setMyMappedStatementMap(mapperStatementMap);

        return myConfiguration;

    }


}
